package com.expression.demo;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.json.JSONUtil;
import com.expression.entity.UserEntity;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.TypedValue;
import org.springframework.expression.common.ExpressionUtils;
import org.springframework.expression.common.TemplateParserContext;
import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.standard.SpelExpression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

import java.time.LocalDate;

/**
 * 表达式demo 可以用作用户自定义一些判断条件
 * 常用的三个对象的含义
 * Expression： 表达式对象
 * SpelExpressionParser：表达式解析器
 * EvaluationContext：上下文
 *
 * @author shixiaodong
 * @date 2022-05-22
 */
@Slf4j
public class DemoTest {
    @Test
    public void test6() {
        UserEntity user = new UserEntity(1, "小明", 20, LocalDateTimeUtil.format(LocalDate.now(), DatePattern.ISO8601_PATTERN));
        StandardEvaluationContext context = new StandardEvaluationContext(user);
        context.setVariable("user", user);
        // 对user中的属性，先进行赋值，在进行比较 得到结果
        String str1 = "#user.id > 20";

        SpelExpressionParser parser = new SpelExpressionParser();
        SpelExpression expression = (SpelExpression) parser.parseExpression(str1);
        Object value = expression.getValue(context);
        String expressionString = expression.getExpressionString();
//        ExpressionState expressionState = new ExpressionState(context);
//        TypedValue typedValue = expression.getAST().getTypedValue(expressionState);
//        ExpressionUtils.convertTypedValue(expressionState.getEvaluationContext(), typedValue, Object.class);
        System.out.println("str1" + expressionString);
        System.out.println("结果为" + value);
        System.out.println(JSONUtil.toJsonStr(user));
    }
    @Test
    public void test4() {
        UserEntity user = new UserEntity(1, "小明", 20, LocalDateTimeUtil.format(LocalDate.now(), DatePattern.ISO8601_PATTERN));
        StandardEvaluationContext context = new StandardEvaluationContext(user);
        context.setVariable("user", user);
        // 对user中的属性，先进行赋值，在进行比较 得到结果
        String str1 = "(#user.age = 19) == 19 && (#user.id = 19) == 19 && #user.name == '小明'";

        SpelExpressionParser parser = new SpelExpressionParser();
        SpelExpression expression = (SpelExpression) parser.parseExpression(str1);
        Object value = expression.getValue(context);
        String expressionString = expression.getExpressionString();
        ExpressionState expressionState = new ExpressionState(context);
        TypedValue typedValue = expression.getAST().getTypedValue(expressionState);
        ExpressionUtils.convertTypedValue(expressionState.getEvaluationContext(), typedValue, Object.class);
        System.out.println("str1" + expressionString);
        System.out.println("结果为" + value);
        System.out.println(JSONUtil.toJsonStr(user));
    }

    @Test
    public void test3() {
        UserEntity user = new UserEntity(1, "小明", 20, LocalDateTimeUtil.format(LocalDate.now(), DatePattern.ISO8601_PATTERN));
        StandardEvaluationContext context = new StandardEvaluationContext(user);
        context.setVariable("user", user);
        String str1 = "#user.id = 19";
        String str2 = "#user.id == 19";
        SpelExpressionParser parser = new SpelExpressionParser();
        // 先给 user 将 id 改为 19
        Expression expression = parser.parseExpression(str1);
        Object value = expression.getValue(context);
        // 在判断 id 是否等于 19
        String expressionString = expression.getExpressionString();
        Expression expression1 = parser.parseExpression(str2);
        Object value2 = expression1.getValue(context);
        System.out.println("v2===>" + value2);
        System.out.println("str1" + expressionString);
        System.out.println(value);
        System.out.println(JSONUtil.toJsonStr(user));
    }

    /**
     * 将 spel 表达式和 实体bean中的饿属性做比较示例
     */
    @Test
    public void test2() {
        SpelExpressionParser parser = new SpelExpressionParser();
        UserEntity user = new UserEntity(1, "小明", 20, LocalDateTimeUtil.format(LocalDate.now(), DatePattern.ISO8601_PATTERN));
        // str 为 spel 表达式，含义为，用户id 大于19 或者年龄大于 19
        String str1 = "#user.id > 19 || #user.age > 19";
        String str2 = "#{#user.age > 19 || #user.name == '小明'}";
        String str3 = "#user.time > '2022-01-10 23:59:59'";
        // 此种方式要想生效  StandardEvaluationContext 的 rootObject 必须是 userEntity的对象
        String str4 = "age > 19 && id > 2";
//        String str3 = "#user.time > T(java.time.LocalDateTime).parse('2022-10-10T23:59:59')";
        // 设置一个评估上下文，设置表达式中引用的变量【javaBean】，进行替换比较
        StandardEvaluationContext context = new StandardEvaluationContext(user);
        // 将user 当做解析对象来进行解析
        context.setVariable("user", user);
        // 解析表达式1 , 标准语法
        Expression expression1 = parser.parseExpression(str1);
        // 解析表达式2, TemplateParserContext 解析
        Expression expression2 = parser.parseExpression(str2, new TemplateParserContext());
        Expression expression3 = parser.parseExpression(str3);
        Expression expression4 = parser.parseExpression(str4);
        // 获取表达式1 和 user 比较的结果
        Boolean value1 = expression1.getValue(context, Boolean.class);
        // 获取表达式2 和user 比较的结果
        Boolean value2 = expression2.getValue(context, Boolean.class);
        Boolean value3 = expression3.getValue(context, Boolean.class);
        Boolean value4 = expression4.getValue(context, Boolean.class);
        System.out.println("获取标准语法解析后的数据  ====> " + value1);
        System.out.println("获取#{}语法解析后的数据  ====> " + value2);
        System.out.println("表达式3解析比较后的结果为===> " + value3);
        System.out.println(value4);
    }

    /**
     * 一个简单的测试
     */
    @Test
    public void test1() {
        String str = "1 + 2";
        ExpressionParser parser = new SpelExpressionParser();
        Expression expression = parser.parseExpression(str);

        Object value = expression.getValue();
        log.info(value.toString());

        EvaluationContext context = new StandardEvaluationContext();
        System.out.println(expression.getValue(context));
    }
}
